方格取数
Time Limit: 5 Sec Memory Limit: 64 MB
Description
在一个n*n的方格里,每个格子里都有一个正整数。从中取出若干数,使得任意两个取出的数所在格子没有公共边,且取出的数的总和尽量大。
第一行一个数n;接下来n行每行n个数描述一个方阵
Output
仅一个数,即最大和
2
1 2
3 5
Sample Output
6
HINT
n<=30
Main idea
给定一个矩阵,取了一个点就不能取上下左右的点了,求能取出的最大价值。
Solution
求的显然是最大权独立集,最大权独立集=总权-最小权覆盖集 ,对于最小权覆盖集我们用最小割来解。
由于取了一个点,不能取上下左右的点,即i±1 or j±1,那么显然是一个二分图,根据奇偶分类。
然后就是一个最小割的模型,我们左边的点向上下左右的点连边,容量为INF (必然不是割),然后跑最大流即可。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 #include <bits/stdc++.h> using namespace std;const int ONE=1001 ;const int TWO=100001 ;const int INF=2147483640 ;int n,m;int tot=0 ;int res,tou,wei,S,T;int Dep[ONE],q[TWO],ans;int a[ONE][ONE],PD[ONE][ONE],BI[ONE][ONE];int next[TWO],first[TWO],go[TWO],w[TWO];int E[ONE];int get () { int res=1 ,Q=1 ;char c; while ( (c=getchar ())<48 || c>57 ) if (c=='-' )Q=-1 ; res=c-48 ; while ( (c=getchar ())>=48 && c<=57 ) res=res*10 +c-48 ; return res*Q; } int Add (int u,int v,int z) { next[++tot]=first[u]; first[u]=tot; go[tot]=v; w[tot]=z; next[++tot]=first[v]; first[v]=tot; go[tot]=u; w[tot]=0 ; } int Bfs () { memset (Dep,0 ,sizeof (Dep)); q[1 ]=0 ; tou=0 ; wei=1 ; Dep[0 ]=1 ; for (int u=0 ;u<=n*n;u++) E[u]=first[u]; while (tou<wei) { int u=q[++tou]; for (int e=first[u];e;e=next[e]) { int v=go[e]; if (Dep[v] || !w[e])continue ; Dep[v]=Dep[u]+1 ; q[++wei]=v; } } return (Dep[T]>0 ); } int Dfs (int u,int Limit) { if (u==T || !Limit) return Limit; int flow=0 ,f; for (int &e=E[u];e;e=next[e]) { int v=go[e]; if (Dep[v]!=Dep[u]+1 || !w[e]) continue ; f=Dfs (v,min (Limit,w[e])); w[e]-=f; w[e^1 ]+=f; Limit-=f; flow+=f; if (!Limit)break ; } return flow; } void Build (int i,int j) { if (BI[i-1 ][j]) Add (BI[i][j],BI[i-1 ][j],INF); if (BI[i][j-1 ]) Add (BI[i][j],BI[i][j-1 ],INF); if (BI[i+1 ][j]) Add (BI[i][j],BI[i+1 ][j],INF); if (BI[i][j+1 ]) Add (BI[i][j],BI[i][j+1 ],INF); } int main () { n=get (); for (int i=1 ;i<=n;i++) for (int j=1 ;j<=n;j++) { a[i][j]=get (); ans+=a[i][j]; if ( i%2 !=j%2 ) PD[i][j]=1 ; BI[i][j]=++tot; } S=0 ; T=n*n+1 ; tot=1 ; for (int i=1 ;i<=n;i++) for (int j=1 ;j<=n;j++) { if (PD[i][j]) Add (S,BI[i][j],a[i][j]); else Add (BI[i][j],T,a[i][j]); if (PD[i][j]) Build (i,j); } while (Bfs ()) res+=Dfs (0 ,INF); printf ("%d" ,ans-res); }